#ifndef __MODBUS_H__
#define __MODBUS_H__
#include <string>
#include "modbus-private.h"
using namespace std;

#define Bit					X01
#define InputBit			X02
#define Register			X03
#define InputRegister		X04

#define ReadBits			ReadX01
#define ReadInputBits		ReadX02
#define ReadRegisters		ReadX03
#define ReadInputRegisters	ReadX04

#define WriteBit			WriteX05
#define WriteRegister		WriteX06
#define WriteBits			WriteX0F
#define WriteRegisters		WriteX10

//RTU.ReadX01:{[slave],[fcode],[offsetH,offsetL],[countH,countL],[crcH,crcL]}
//RTU.ReadX02:{[slave],[fcode],[offsetH,offsetL],[countH,countL],[crcH,crcL]}
//RTU.ReadX03:{[slave],[fcode],[offsetH,offsetL],[countH,countL],[crcH,crcL]}
//RTU.ReadX04:{[slave],[fcode],[offsetH,offsetL],[countH,countL],[crcH,crcL]}
//RTU.Response:{[slave],[fcode],[bcount],[data...],[crc1,crc0]}
//
//RTU.WriteX05:{[slave],[fcode],[offsetH,offsetL],[valueH,valueL],[crcH,crcL]}
//RTU.WriteX06:{[slave],[fcode],[offsetH,offsetL],[valueH,valueL],[crcH,crcL]}
//RTU.Response:{[slave],[fcode],[offsetH,offsetL],[valueH,valueL],[crcH,crcL]}
//
//RTU.WriteX0F:{[slave],[fcode],[offsetH,offsetL],[countH,countL],[bcount],[data...],[crcH,crcL]}
//RTU.WriteX10:{[slave],[fcode],[offsetH,offsetL],[countH,countL],[bcount],[data...],[crcH,crcL]}
//RTU.Response:{[slave],[fcode],[offsetH,offsetL],[countH,countL],[crcH,crcL]}
//
//TCP{[idH,idL],[lenHH,lenHL,lenLH,lenLL],RTU}

typedef union
{
    uint8_t  bits[256];
    uint16_t regs[128];
} ModbusData;
class Modbus
{
protected:
    modbus_t*	ctx;
    ModbusData	data;
public:
    uint8_t debug;
    uint8_t fcode;
    uint8_t count;
    uint8_t slave;
    uint8_t offset;
public:
    Modbus(void);
    ~Modbus(void);
public:
    void Destroy(void);
    bool SetDebug(bool);
    bool SetSlave(uint8_t);
    bool SetTimeout(int);
public:
    const uint16_t operator[](uint8_t)const;
};
class ModbusClient: public Modbus
{
public:
    ModbusClient(const string& ip="", int port=3788, bool debug=false);
    ModbusClient(const string&, int, int, int, int, bool debug=false);
public:
    bool Create(const string&, int port=3788, bool debug=false);
    bool Create(const string&, int, int, int, int, bool debug=false);
public:
    bool ReadX01(int, int);
    bool ReadX02(int, int);
    bool ReadX03(int, int);
    bool ReadX04(int, int);
public:
    bool WriteX05(int, uint8_t);
    bool WriteX06(int, uint16_t);
    bool WriteX0F(int, int, uint8_t*);
    bool WriteX10(int, int, uint16_t*);
};
class ModbusMapping : public Modbus
{
protected:
    uint16_t nullvalue;
    modbus_mapping_t *mapping;
public:
    ModbusMapping(void);
    ~ModbusMapping(void);
public:
    void Free(void);
    bool Mapping(int start_bits             = 0, int nb_bits            = 65535, 
	             int start_input_bits       = 0, int nb_input_bits      = 65535, 
	             int start_registers        = 0, int nb_registers       = 65535, 
	             int start_input_registers  = 0, int nb_input_registers = 65535);
public:
    uint8_t&  X01(uint16_t);
    uint8_t&  X02(uint16_t);
    uint16_t& X03(uint16_t);
    uint16_t& X04(uint16_t);
};
class ModbusServer : public ModbusMapping
{
protected:
    int ssock;
public:
    ~ModbusServer(void);
    ModbusServer(const string& ip="", int port=3788, bool debug=false);
    ModbusServer(const string&, int baud, int parity, int bsize, int stop, bool debug=false);
public:
    bool Create(const string&, int port=3788, bool debug=false);
    bool Create(const string&, int baud, int parity, int bsize, int stop, bool debug=false);
public:
    int Receive(void);
};

#endif//__MODBUS_H__
